//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-02-01
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Xml.Serialization;
using JetBrains.Annotations;
using LargoCommon.Abstract;
using LargoCommon.Interfaces;
namespace LargoCommon.Music
{
///
/// Musical Bar.
///
public class MusicalBar : IAbstractBar
{
#region Fields
/// Cluster level for tick.
private readonly Dictionary clusterLevelForTick;
///
/// List of harmonic clusters.
///
private List harmonicClusters;
///
/// The elements.
///
private List elements;
///
/// The count of tones
///
private int countOfTones;
///
/// The value of melodic ticks
///
private int valueOfMelodicTicks;
///
/// The value of rhythmic ticks
///
private int valueOfRhythmicTicks;
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public MusicalBar() {
this.clusterLevelForTick = new Dictionary();
this.elements = new List();
this.TempoNumber = 120;
this.HarmonicBar = new HarmonicBar(0, 0);
}
///
/// Initializes a new instance of the MusicalBar class. Serializable.
///
/// The bar number.
/// The body.
public MusicalBar(int barNumber, MusicalBody body)
: this() {
this.Body = body;
this.BarNumber = barNumber;
}
/// Initializes a new instance of the class.
/// The given musical block.
/// The given code.
/// Length of the given.
public MusicalBar(MusicalBlock givenBlock, string givenCode, int givenLength) : this() {
this.Body = givenBlock.Body;
this.elements = new List();
this.IsEmpty = string.IsNullOrEmpty(givenCode);
this.SystemLength = givenLength;
this.StructuralCode = givenCode;
var chord = new HarmonicStructure(this.Body.Context.Header.System.HarmonicSystem, givenCode); //// HarmonicSystem.GetHarmonicSystem(DefaultValue.HarmonicOrder)
this.HarmonicBar.SetStructure(chord);
}
///
/// Initializes a new instance of the class.
///
/// The given musical block.
/// The mark bar.
/// Thrown when a method Contract has been broken.
public MusicalBar(MusicalBlock givenBlock, XElement markBar) {
Contract.Requires(markBar != null);
if (markBar == null) {
return;
}
this.Body = givenBlock.Body;
this.elements = new List();
var xcell = markBar.Element("Chord");
this.SystemLength = XmlSupport.ReadIntegerAttribute(markBar.Attribute("Length"));
this.IsEmpty = XmlSupport.ReadBooleanAttribute(markBar.Attribute("IsEmpty"));
if (xcell != null) {
this.StructuralCode = XmlSupport.ReadStringAttribute(xcell.Attribute("Code"));
}
this.HarmonicStructure = new HarmonicStructure(givenBlock.Header.System.HarmonicSystem, this.StructuralCode); //// HarmonicSystem.GetHarmonicSystem(DefaultValue.HarmonicOrder)
//// this.HarmonicPotential = XmlSupport.ReadByteAttribute(markCell.Attribute("HarmonicPotential"));
var xelements = markBar.Elements("Element");
foreach (var xe in xelements) {
MusicalElement element = new MusicalElement(xe, this.Header);
int barNumber = XmlSupport.ReadIntegerAttribute(xe.Attribute("Bar"));
int lineIndex = XmlSupport.ReadIntegerAttribute(xe.Attribute("LineIndex"));
var line = givenBlock.ContentLines[lineIndex];
element.Bar = this;
element.Line = line;
this.Elements.Add(element);
}
}
#endregion
#region Properties - Xml
/// Gets Xml representation.
/// Property description.
public virtual XElement GetXElement {
get {
XElement xbar = new XElement("Bar");
xbar.Add(new XAttribute("Number", this.BarNumber));
//// Lines
XElement xelements = new XElement("Elements");
//// Musical Element to XML
foreach (MusicalElement element in this.Elements.Where(element => element != null)) {
//// mtrack.MusicalBlock = givenMusicalBlock;
var xelement = element.GetXElement;
xelements.Add(xelement);
}
xbar.Add(xelements);
return xbar;
}
}
#endregion
#region Properties - Harmonic Status
///
/// Gets Harmonic Status.
///
/// Property description.
public HarmonicChange HarmonicStatus { get; private set; }
///
/// Gets a value indicating whether this instance has harmonic motive.
///
///
/// Is true if this instance has harmonic motive; otherwise, false.
///
public bool HasHarmonicMotive {
get {
if (this.HarmonicStatus == null) {
return false;
}
var hm = this.HarmonicStatus.HarmonicMotive;
return hm?.HarmonicStream.HarmonicBars != null && hm.HarmonicStream.HarmonicBars.Any();
}
}
///
/// Gets or sets current harmonical bar.
///
///
/// Property description.
///
[XmlIgnore]
public HarmonicBar HarmonicBar { get; set; }
/// Gets or sets the harmonic structure.
/// The harmonic structure.
public HarmonicStructure HarmonicStructure {
get => this.HarmonicBar?.HarmonicStructures?.FirstOrDefault();
set => this.HarmonicBar.SetStructure(value);
}
#endregion
#region Properties - Tempo Status
/// Gets or sets class of melodic part.
/// Property description.
public int TempoNumber { get; set; }
#endregion
#region Properties
///
/// Gets or sets the body.
///
///
/// The body.
///
public MusicalBody Body { get; set; }
///
/// Gets the header.
///
///
/// The header.
///
public MusicalHeader Header => this.Body.Context.Header;
/// Gets or sets the zero-based index of the bar.
/// The bar index.
public int BarIndex { get; set; }
/// Gets or sets number o bar.
/// Property description.
[XmlAttribute]
public int BarNumber {
get => this.BarIndex + 1;
set => this.BarIndex = value - 1;
}
/// Gets or sets the system length.
/// The length of the system.
public int SystemLength { get; set; }
/// Gets or sets the structural code.
/// The structural code.
public string StructuralCode { get; set; }
//// public byte HarmonicPotential { get; set; }
/// Gets or sets a value indicating whether this object is empty.
/// True if this object is empty, false if not.
public bool IsEmpty {
get => (this.HarmonicBar == null) || this.HarmonicBar.IsEmpty;
set {
//// this.Status.HarmonicBar.IsEmpty = value;
}
}
///
/// Gets the elements.
///
///
/// The elements.
///
public IList Elements => this.elements;
///
/// Gets the rhythmic order divisor.
///
///
/// The rhythmic order divisor.
///
public byte RhythmicOrderDivisor {
get {
var factor = 0; //// rstruct.GSystem.Order;
foreach (var elem in this.elements) {
if (elem.Status.RhythmicStructure == null || elem.Status.RhythmicStructure.Level == 0) {
continue;
}
var header = this.Body.Context.Header;
var rhythmicShape = new RhythmicShape(header.System.RhythmicOrder, elem.Status.RhythmicStructure);
var listDistances = rhythmicShape.BitDistances;
foreach (byte d in listDistances) {
if (factor == 0) {
factor = d;
}
else {
factor = (int)MathSupport.GreatestCommonDivisor(factor, d);
}
}
}
return (byte)(factor == 0 ? 1 : factor);
}
}
/// Gets or sets time tag.
/// In ticks according to order of rhythmical system..
[XmlIgnore]
public int TimePoint { get; set; }
/// Gets or sets common rhythmical shape.
/// Property description.
public RhythmicShape CommonRhythmicShape { get; set; }
#endregion
#region Internal Properties
/// Gets list of harmonic clusters.
/// Property description.
[XmlIgnore]
public Collection HarmonicClusters {
get {
Contract.Ensures(Contract.Result>() != null);
if (this.harmonicClusters == null) {
this.harmonicClusters = new List();
}
/* 2019/09 if (this.harmonicClusters == null) {
throw new InvalidOperationException("List of clusters is null.");
} */
return new Collection(this.harmonicClusters);
}
}
///
/// Gets or sets the previous bar.
///
///
/// Property description.
///
[XmlIgnore]
public MusicalBar PreviousBar { get; set; }
/// Gets or sets the previous bar.
/// Property description.
/// Returns value.
[XmlIgnore]
public MusicalBar NextBar { get; set; }
#endregion
#region Tone Properties
///
/// Gets the tones.
///
///
/// The tones.
///
public IList Tones {
get {
var ts = new List();
foreach (var elem in this.elements) {
ts.AddRange(elem.Tones);
}
return ts;
}
}
///
/// Gets the count of tones.
///
///
/// The count of tones.
///
[UsedImplicitly]
public int CountOfTones {
get {
if (this.countOfTones > 0) {
return this.countOfTones;
}
this.countOfTones = this.Tones.Count;
return this.countOfTones;
}
}
///
/// Gets the melodic tones.
///
///
/// The melodic tones.
///
public IList MelodicTones {
get {
var ts = new List();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var elem in this.elements) {
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var t in elem.Tones) {
if (t is MusicalTone mt && mt.IsTrueTone) {
ts.Add(mt);
}
}
}
return ts;
}
}
#endregion
#region Relation to harmonic motive
/// Gets or sets a value indicating whether is block nested.
/// Is bar nested from other block.
public int NumberInHarmonicMotive { get; set; }
///
/// Gets or sets a value indicating whether [last in harmonic motive].
///
///
/// True if [is last in harmonic motive]; otherwise, false.
///
public bool IsLastInHarmonicMotive { get; set; }
#endregion
#region ToString properties
/// Gets Write particular structures to string.
/// Returns value.
/// General musical property.
public string ChordsToString => this.HarmonicBar.ChordsToString;
/// Gets Write particular structures to string.
/// Returns value.
/// General musical property.
public string PureChordsToString => this.HarmonicBar.PureChordsToString;
/// Gets String representation of clusters.
/// Property description.
/// Returns value.
public string ClustersToString {
get {
if (this.CommonRhythmicShape == null) {
return string.Empty;
}
var rhyShape = this.CommonRhythmicShape;
var s = new StringBuilder();
//// s.Append("Clusters:"); //// +"\n"
var shapeLevel = this.CommonRhythmicShape.Level;
for (byte level = 0; level < shapeLevel; level++) {
var hc = this.harmonicClusters != null && level < this.HarmonicClusters.Count ? this.HarmonicClusterAtLevel(level) : null;
if (hc == null) {
continue;
}
if (level == 0) {
s.AppendFormat(CultureInfo.CurrentCulture, "{0,4}:\n", this.BarNumber.ToString("D", CultureInfo.CurrentCulture.NumberFormat));
}
else {
s.Append(" ");
}
//// Cluster
s.AppendFormat(CultureInfo.CurrentCulture, "{0,16}", hc); //// {0,12}
s.Append(string.Format(CultureInfo.CurrentCulture, "({0} ticks) ", rhyShape.DistanceAtLevel(level).ToString("D", CultureInfo.CurrentCulture.NumberFormat)));
s.Append("\t\t ");
if (hc.HarmonicStructure != null) {
s.AppendFormat(CultureInfo.CurrentCulture, hc.HarmonicStructure.ToneSchema.PadRight(15), CultureInfo.CurrentCulture);
if (hc.HarmonicStructure.HarmonicModality != null) {
s.Append(string.Format(CultureInfo.CurrentCulture, " ({0})", hc.HarmonicStructure.HarmonicModality.ToneSchema)); //// ????
}
}
s.Append("\n");
}
return s.ToString().Trim();
}
}
#endregion
/// Gets a list of identifiers.
/// A list of identifiers.
public IList Identifiers {
get {
var items = new List();
string s;
var item = new KeyValuePair("Bar number", this.BarNumber.ToString());
items.Add(item);
item = new KeyValuePair("Time point", this.TimePoint.ToString());
items.Add(item);
item = new KeyValuePair("Harmonic modality", this.HarmonicBar?.HarmonicModality?.ToString());
items.Add(item);
item = new KeyValuePair("Structures", this.HarmonicBar?.SimpleStructuralOutline);
items.Add(item);
item = new KeyValuePair("Structures in detail", this.HarmonicBar?.StructuralOutline);
items.Add(item);
var rhythmicOrder = this.HarmonicBar?.Header?.System?.RhythmicOrder; //// Body.Context.Header.System.RhythmicOrder;
if (rhythmicOrder != null) {
var barBitRange = new BitRange((byte)rhythmicOrder, 0, (byte)rhythmicOrder);
var harmonicStructure = this.HarmonicBar.PrevailingHarmonicStructure(barBitRange, out var simpleHarmony);
item = new KeyValuePair("Prevailing structure", harmonicStructure?.ToneSchema);
items.Add(item);
item = new KeyValuePair("Simple harmony", simpleHarmony.ToString());
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanRhythmicMobility);
item = new KeyValuePair("Mean rhythmic mobility", s);
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanRhythmicTension);
item = new KeyValuePair("Mean rhythmic tension", s);
items.Add(item);
}
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanConsonance);
item = new KeyValuePair("Mean consonance", s);
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanContinuity);
item = new KeyValuePair("Mean continuity", s);
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanImpulse);
item = new KeyValuePair("Mean impulse", s);
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.HarmonicBar?.MeanPotential);
item = new KeyValuePair("Mean potential", s);
items.Add(item);
s = string.Format(CultureInfo.CurrentCulture.NumberFormat, "{0,6:F2} ", this.TempoNumber);
item = new KeyValuePair("Tempo number", this.TempoNumber.ToString());
items.Add(item);
return items;
}
}
#region Public methods
///
/// Elements the of line.
///
/// The track identifier.
/// Returns value.
public MusicalElement ElementOfLine(Guid lineIdent) {
var element = (from v in this.Elements
where v.Line.LineIdent == lineIdent
select v).FirstOrDefault();
//// var selectedList = (from element in list orderby element.Point.BarNumber
//// select element).ToList();
return element;
}
///
/// Counts the of ticks.
///
/// if set to true [break for rests].
/// Type of the line.
///
/// Returns value.
///
public int CountOfSelectedTicks(bool breakForRests, MusicalLineType lineType) {
var rhythmicOrder = this.Body.Context.Header.System.RhythmicOrder;
var bitArray = new BitArray(rhythmicOrder);
//// for (byte tick = 0; tick < rhythmicOrder; tick++) {
foreach (var elem in this.Elements) {
if (!elem.MusicalLine.IsSelected || elem.MusicalLine.FirstStatus.LineType != lineType) {
continue;
}
if (elem.Status.RhythmicStructure == null) {
continue;
}
//// var binStruct = elem.Status.RhythmicStructure.BinaryStructure(breakForRests);
//// bitArray = bitArray.Or(binStruct.BitArray);
var binStructArray = elem.Status.RhythmicStructure.BitArray(breakForRests);
bitArray = bitArray.Or(binStructArray);
}
byte sum = 0;
foreach (var bit in bitArray) {
sum += (byte)(((bool)bit) ? 1 : 0);
}
return sum;
}
///
/// Resets the values of ticks.
///
public void ResetValuesOfTicks() {
this.valueOfMelodicTicks = 0;
this.valueOfRhythmicTicks = 0;
}
#endregion
#region Public methods
#region Apply Changes
///
/// Applies the harmonic change.
///
/// The harmonic change.
public void ApplyHarmonicChange(HarmonicChange harmonicChange) {
//// Contract.Requires(harmonicChange != null);
if (harmonicChange == null) {
return;
}
this.HarmonicStatus = harmonicChange;
}
///
/// Applies the tempo change.
///
/// The tempo change.
public void ApplyTempoChange(TempoChange tempoChange) {
//// Contract.Requires(harmonicChange != null);
if (tempoChange == null) {
return;
}
this.TempoNumber = tempoChange.TempoNumber;
}
#endregion
/* Clone bar - Not needed, not used.
/// Makes a deep copy of the MusicalBarStatus object.
/// Returns object.
public object Clone() {
var tmc = new BarStatus(this.BarNumber) {
HarmonicStatus = this.HarmonicStatus,
TempoNumber = this.TempoNumber
};
if (this.HarmonicBar != null) {
tmc.HarmonicBar = (HarmonicBar)this.HarmonicBar.Clone();
}
return tmc;
} */
///
/// Sets the T harmonic motive bar.
///
/// The value.
public void SetHarmonicBar(HarmonicBar value) {
if (value == null) {
throw new ArgumentException("Empty harmonic bar!");
}
if (value.Header == null) {
value.Header = this.Body.Context.Header;
}
this.HarmonicBar = (HarmonicBar)value.Clone(); //// value
if (this.HarmonicBar.IsEmpty) {
this.HarmonicBar.CheckStructures();
}
var rhythmicOrder = this.HarmonicBar.Header.System.RhythmicOrder;
var metre = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Shape, rhythmicOrder);
var metricStructuralCode = this.HarmonicBar.GetBarMetricCode;
this.HarmonicBar.RhythmicShape = RhythmicShape.GetNewRhythmicShape(metre, metricStructuralCode);
//// Have to be clone of bar above ?!?!?!?
//// else { this.HarmonicBar.RegenerateStructures(); }
}
///
/// Gets the element.
///
/// The line identifier.
/// Returns value.
public MusicalElement GetElement(Guid lineIdent) {
var element = (from elem in this.elements where elem.Line.LineIdent == lineIdent select elem).FirstOrDefault();
return element;
}
/// Makes a deep copy of the MusicalPitch object.
/// Returns object.
public object Clone() {
var bar = new MusicalBar(this.BarNumber, this.Body) {
TimePoint = this.TimePoint,
CommonRhythmicShape = this.CommonRhythmicShape
};
foreach (var element in this.Elements) {
var newElement = (MusicalElement)element.Clone();
newElement.Bar = bar;
bar.Elements.Add(newElement);
}
bar.MakeHarmonicClusters();
return bar;
}
///
/// Sets the modality to structures.
///
/// The minimum modality level.
public void SetModalityToStructures(byte minModalityLevel) {
foreach (var harStr in this.HarmonicBar.HarmonicStructures.Where(harStr => this.Body.Bars != null && this.Body != null)) {
harStr.HarmonicModality = this.HarmonicModalityFromStructures(minModalityLevel);
}
}
///
/// Returns harmonic modality from all harmonic structures.
///
/// The minimum modality level.
///
/// Returns value.
///
public HarmonicModality HarmonicModalityFromStructures(byte minModalityLevel) {
if (this.HarmonicBar?.HarmonicStructures == null || this.HarmonicBar?.HarmonicStructures?.Count <= 0) {
return null;
}
var bits = this.BitsOccupiedByHarmony(minModalityLevel);
var firstStructure = this.HarmonicBar.HarmonicStructures[0];
var modality = firstStructure != null ? HarmonicModality.GetNewHarmonicModality(firstStructure.HarmonicSystem, bits) : null;
return modality;
}
///
/// Sets the elements.
///
/// The given elements.
public void SetElements(IList givenElements) {
this.elements = (List)givenElements;
}
///
/// Writes musical block to Scores - Orchestration.
///
///
/// Returns value.
///
public OrchestraStrip OrchestraStrip() {
var strip = new OrchestraStrip();
//// Cycle through all the sequence
//// byte number = 0;
this.elements.ForEach(mt => {
if (mt != null) { //// && !mt.IsEmpty && mt.IsSelected
var barTones = mt.SingleMelodicTones();
if (barTones.Count > 0) {
//// MelodicFunction melodicType = barTones.DetermineMelodicType(mbar.HarmonicBar);
//// MusicalLoudness loudness = barTones.MeanLoudness;
var mstatus = mt.Status;
if (mstatus == null) {
return;
}
//// var instrument = new GeneralChannel(InstrumentGenus.Melodical, mstatus.Instrument, mstatus.Channel);
if (!mstatus.Instrument.IsEmpty) { //// 2019/10
var track = new OrchestraTrack(barTones.MeanOctave, mstatus.Instrument);
strip.OrchestraTracks.Add(track);
}
//// number++;
}
else {
var barStrikes = mt.Tones;
if (barStrikes.Count > 0) {
//// MelodicFunction melodicType = barTones.DetermineMelodicType(mbar.HarmonicBar);
//// MusicalLoudness loudness = barTones.MeanLoudness;
var mstatus = mt.Status;
if (mstatus == null) {
return;
}
//// var instrument = new GeneralChannel(InstrumentGenus.Melodical, mstatus.Instrument, mstatus.Channel);
if (!mstatus.Instrument.IsEmpty) { //// 2019/10
var track = new OrchestraTrack(mstatus.Instrument);
strip.OrchestraTracks.Add(track);
}
//// number++;
}
}
}
});
strip.RecomputeProperties();
return strip;
}
///
/// Swaps the harmonic with.
///
/// The given bar.
public void SwapHarmonyWith(MusicalBar givenBar) {
Contract.Requires(givenBar != null);
var harmonicBar = givenBar.HarmonicBar;
var newHarmonicBar = (HarmonicBar)harmonicBar.Clone();
newHarmonicBar.BarNumber = givenBar.BarNumber;
givenBar.SetHarmonicBar(newHarmonicBar);
this.SetHarmonicBar(harmonicBar);
}
///
/// Melodic tones around.
///
/// The bar numbers back.
/// The bar numbers forward.
///
/// Returns value.
///
public IEnumerable MelodicTonesAround(int barNumbersBack, int barNumbersForward) {
var ts = new List();
foreach (var elem in this.Elements) {
ts.AddRange(elem.MelodicTonesAround(barNumbersBack, barNumbersForward));
}
return ts;
}
///
/// Surroundings the bars.
///
/// The bars before.
/// The bars after.
/// Returns value.
public IList SurroundingBars(byte barsBefore, byte barsAfter) {
var musicalBars = new List();
var currentBar = this;
musicalBars.Add(currentBar);
for (byte i = 0; i <= barsBefore; i++) {
if (currentBar == null) {
break;
}
currentBar = currentBar.PreviousBar;
if (currentBar != null) {
musicalBars.Add(currentBar);
}
}
currentBar = this;
for (byte i = 0; i <= barsAfter; i++) {
if (currentBar == null) {
break;
}
currentBar = currentBar.NextBar;
if (currentBar != null) {
musicalBars.Add(currentBar);
}
}
return musicalBars;
}
///
/// Compose rhythm of lines in given bar.
///
public void FillTracksWithRhythm() {
//// Ordering is not needed here, motives are loaded from status //// All - not only (&& mt.Status != null)
if (this.Body.Context.Settings.ParallelMode) {
Parallel.ForEach(
this.Elements,
mt => {
if (mt == null) {
return;
}
mt.FillWithRhythm();
});
}
else {
this.elements.ForEach(mt => {
if (mt == null) {
return;
}
mt.FillWithRhythm();
});
}
}
///
/// Transfers the status to tones.
///
public void SendStatusToTones() {
foreach (var element in this.Elements) {
if (element?.Status == null) {
continue;
}
var status = element.Status;
foreach (var mt in element.Tones) {
if (!(mt is MusicalStrike mtone)) {
continue;
}
mtone.InstrumentNumber = status.Instrument.Number;
mtone.Staff = status.Staff;
mtone.Loudness = status.Loudness;
}
}
}
///
/// Eliminates the parallel melodies.
/// Correct melodic type - eliminate parallel individualized melodic voices.
///
public void EliminateParallelMelodies() {
var ems = this.Elements;
var hasMelody = false;
foreach (var me in ems) {
if (me == null || me.Line.Purpose != LinePurpose.Composed || me.Status == null) {
continue;
}
var mstatus = me.Status;
if (mstatus == null) {
continue;
}
var melFilling = mstatus.MelodicFunction == MelodicFunction.MelodicFilling;
var melMotion = mstatus.MelodicFunction == MelodicFunction.MelodicMotion;
if (hasMelody) {
if (melFilling) {
mstatus.MelodicFunction = MelodicFunction.HarmonicFilling;
}
else {
if (melMotion) {
mstatus.MelodicFunction = MelodicFunction.HarmonicMotion;
}
}
}
else {
hasMelody = melFilling || melMotion;
}
}
}
#endregion
#region Planned Tones
///
/// Prepare Planned Tones.
///
public void PreparePlannedTones() {
//// var hs = this.Body.Context.Header.System.HarmonicSystem;
var hm = this.HarmonicModalityFromStructures(MusicalSettings.Singleton.MinimalModalityLevel);
////HarmonicModality hm = MusicalTrackEngine.DetermineHarmonicModality(musicalBar, null, HarmonicModalizationType.Consecutive);
if (hm == null || hm.Level <= 1) { //// 2016/07
return;
}
foreach (var elem in this.Elements) {
if (elem == null || elem.Status?.LocalPurpose != LinePurpose.Composed) {
continue;
}
//// bool figural = mtrack.CurrentMelodicStructure != null; //// mp.Status.HasMelodicMotive
//// if ((this.Status == null) || !figural) { continue; }
var tones = elem.Tones;
if (tones != null) {
/*bool fromMelodicStructure = false;
if (fromMelodicStructure) {
elem.ProjectIntoPlannedTones(hs, hm, tones);
}
else {
elem.Status.PlannedTones = tones;
}*/
}
}
}
#endregion
#region Public Clusters
///
/// Makes common rhythmical shape, i.e. elementary rhythm from all parts.
///
/// Returns value.
public bool MakeCommonRhythmicShape() {
this.CommonRhythmicShape = this.DetermineCommonRhythmicShape(true); //// , this.BarNumber
if (this.CommonRhythmicShape == null) {
return false;
}
this.AssignClusterLevelsForTicks();
return true;
}
///
/// Add harmonic cluster to the list of clusters.
///
/// Given Cluster.
public void AddHarmonicCluster(HarmonicCluster givenCluster) {
Contract.Requires(givenCluster != null);
this.HarmonicClusters.Add(givenCluster);
givenCluster.BarNumber = this.BarNumber;
}
///
/// Makes harmonic clusters for this bar.
///
public void MakeHarmonicClusters() { //// byte rhythmicOrder, IEnumerable givenMusicalTracks
//// Contract.Requires(givenMusicalTracks != null);
//// var musicalTracks = givenMusicalLines as IList ?? givenMusicalTracks.ToList();
if (!this.MakeCommonRhythmicShape()) { //// this.Number, true //// rhythmicOrder, musicalTracks
return;
}
this.harmonicClusters = new List();
if (this.CommonRhythmicShape == null) {
return;
}
var level = this.CommonRhythmicShape.Level;
for (byte lev = 0; lev < level; lev++) {
if (this.CommonRhythmicShape == null) {
continue;
}
var hc = this.MakeHarmonicClusterAtLevel(lev);
if (hc == null) {
continue;
}
this.AddHarmonicCluster(hc);
}
}
/// Re-compute properties of harmonic clusters in this bar.
/// Given range.
public void RecomputeHarmonicClusters(BitRange range) {
Contract.Requires(this.CommonRhythmicShape != null);
if (range == null) {
return;
}
//// byte lastLevel = 127;
var rhyShape = this.CommonRhythmicShape;
var levelFrom = rhyShape.LevelOfBit(range.BitFrom);
var levelTo = rhyShape.LevelOfBit(range.BitTo);
for (var level = levelFrom; level <= levelTo; level++) {
if (level >= this.HarmonicClusters.Count) {
break;
}
var harCluster = this.HarmonicClusters[level];
harCluster?.Recompute();
}
}
/// Returns harmonic clusters at given place.
/// Requested level.
/// Returns value.
public HarmonicCluster HarmonicClusterAtLevel(byte givenLevel) {
Contract.Requires(givenLevel < this.HarmonicClusters.Count);
if (this.HarmonicClusters == null || this.HarmonicClusters.Count == 0 || givenLevel >= this.HarmonicClusters.Count) {
return null;
}
var harCluster = this.HarmonicClusters[givenLevel];
return harCluster;
}
/// Returns harmonic clusters at given tick.
/// Requested tick.
/// Returns value.
public HarmonicCluster HarmonicClusterAtTick(byte givenTick) {
var rhyShape = this.CommonRhythmicShape;
if (rhyShape == null) {
return null;
}
var level = this.clusterLevelForTick[givenTick];
//// this.CommonRhythmicShape.LevelOfBit(givenTick);
if (level >= this.HarmonicClusters.Count) {
return null;
}
var harCluster = this.HarmonicClusters[level];
return harCluster;
}
#endregion
#region Common Rhythmic Shape
///
/// Common Rhythmic Shape.
///
/// If set to true [consider current status].
///
/// Returns value.
///
/// Incompatible rhythmical orders.
public RhythmicShape DetermineCommonRhythmicShape(bool considerTrackStatus) {
var rhythmicOrder = this.Body.Context.Header.System.RhythmicOrder;
//// in variable "bits" is assembled the common rhythmic shape
var bits = new BitArray(rhythmicOrder);
bits.SetAll(false);
//// .Where(mt => mt != null && mt.IsSelected)
foreach (var mt in this.Elements.Where(mt => mt.Status?.LineType == MusicalLineType.Melodic)) {
if (considerTrackStatus) {
if (mt.Status.RhythmicStructure == null) {
var tones = mt.Tones; ////Track.MusicalTonesInBar(givenBarNumber);
if (tones != null) {
var rstruct = new RhythmicStructure(rhythmicOrder, tones);
mt.Status.RhythmicStructure = rstruct;
}
}
if (mt.Status.RhythmicStructure == null) {
continue;
}
}
var binStr = mt.Status.RhythmicStructure.BinaryStructure(false); //// 2015/01
if (binStr == null) {
continue;
}
if (binStr.BitArray.Length == bits.Length) { //// 2012/06 //// null test not needed (resharper)
bits = bits.Or(binStr.BitArray);
}
else {
throw new InvalidOperationException("Incompatible rhythmical orders.");
}
}
var commonRhythmicShape = RhythmicShape.GetNewRhythmicShape(this.Body.Context.Header.System.RhythmicSystem, bits);
return commonRhythmicShape;
}
///
/// Common Rhythmic Structure.
///
///
/// Returns value.
///
public RhythmicStructure CommonRhythmicStructure() {
Contract.Requires(this.Elements != null);
var rhythmicOrder = this.Body.Context.Header.System.RhythmicOrder;
//// in variable "elements" is assembled the common rhythmic shape
var list = new short[rhythmicOrder];
//// each of elements = 0
foreach (var mt in this.Elements.Where(mt => mt.Status.LineType == MusicalLineType.Melodic)) {
var tones = mt.Tones; //// Track.MusicalTonesInBar(givenBarNumber);
if (tones != null) {
var rhyStr = new RhythmicStructure(rhythmicOrder, tones);
for (byte tick = 0; tick < rhythmicOrder; tick++) {
if (rhyStr.ElementList == null || tick > rhyStr.ElementList.Count - 1) { //// 2014/01
break;
}
var elem = rhyStr.ElementList[tick];
if (list[tick] == 0 && elem > 0) {
list[tick] = elem;
}
}
}
}
var rs = new RhythmicStructure {
GSystem = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, rhythmicOrder)
};
rs.SetElementList(new Collection(list));
return rs;
}
///
/// Gets the value of ticks.
///
/// Type of the line.
/// Returns value.
///
/// The value of ticks.
///
public int ValueOfTicks(MusicalLineType lineType) {
if (lineType == MusicalLineType.Melodic) {
if (this.valueOfMelodicTicks > 0) {
return this.valueOfMelodicTicks;
}
}
if (lineType == MusicalLineType.Rhythmic) {
if (this.valueOfRhythmicTicks > 0) {
return this.valueOfRhythmicTicks;
}
}
var value1 = this.CountOfSelectedTicks(false, lineType);
//// var value2 = this.CountOfSelectedTicks(true, lineType);
//// int value = (2 * value1) + value2 + this.CountOfTones;
return value1;
}
#endregion
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
var s = new StringBuilder();
s.AppendFormat(CultureInfo.CurrentCulture, "Bar n.{0,3}: ", this.BarNumber); //\r\n
s.Append(this.HarmonicBar);
s.Append(this.ChordsToString);
s.Append(this.ClustersToString);
return s.ToString();
}
/// String representation of the object.
/// Returns value.
public string NumberToString() {
var s = new StringBuilder();
s.AppendFormat(CultureInfo.CurrentCulture, "{0,3}: ", this.BarNumber);
return s.ToString();
}
#endregion
#region Private methods
///
/// Makes harmonic cluster for a given rhythmical place.
///
/// Requested level.
///
/// Returns value.
///
private HarmonicCluster MakeHarmonicClusterAtLevel(byte givenLevel) {
//// Contract.Requires(musicalTracks != null);
Contract.Requires(this.CommonRhythmicShape != null);
if (this.HarmonicBar == null) {
return null;
}
var tick = this.CommonRhythmicShape.PlaceAtLevel(givenLevel);
var duration = this.CommonRhythmicShape.DistanceAtLevel(givenLevel);
var harmonicStructure = this.HarmonicBar.HarmonicStructureAtTick(tick);
var harCluster = new HarmonicCluster(harmonicStructure, tick, duration);
foreach (var mt in from elem in this.Elements
where elem?.Tones != null //// && mtrack.IsSelected
where elem.Status?.LineType == MusicalLineType.Melodic
select elem.MusicalToneAt(tick, elem.Status.RhythmicStructure) as MusicalTone
into mt
where mt != null && mt.ToneType == MusicalToneType.Melodic
select mt) {
harCluster.AddMelodicTone(mt);
}
harCluster.Recompute();
return harCluster;
}
///
/// Assign Cluster Levels For Ticks.
///
private void AssignClusterLevelsForTicks() {
Contract.Requires(this.CommonRhythmicShape != null);
var rhyShape = this.CommonRhythmicShape;
for (byte tick = 0; tick < rhyShape.Order; tick++) {
var level = rhyShape.LevelOfBit(tick);
this.clusterLevelForTick[tick] = level;
}
}
#endregion
///
/// Bit sets the occupied by harmony.
///
/// The min modality level.
/// Returns value.
private BitArray BitsOccupiedByHarmony(byte minModalityLevel) {
var harmonicOrder = this.Body.Context.Header.System.HarmonicOrder;
var bits = new BitArray(harmonicOrder); //// long number = 0L;
var bars = this.SurroundingBars(3, 3);
foreach (var currentBar in bars.Where(currentBar => currentBar?.HarmonicBar.HarmonicStructures != null)) {
bits = currentBar.HarmonicBar.HarmonicStructures.Where(hs => hs != null).Aggregate(bits, (current, hs) => current.Or(hs.BitArray));
var bitLevel = (from bool m in bits where m select m).Count();
if (bitLevel >= minModalityLevel) {
break;
}
}
return bits;
}
}
}